package com.htfyun.factorytest.engineer_test;

import android.content.Context;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.os.Bundle;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.Nullable;

import com.blankj.utilcode.util.VolumeUtils;
import com.htfyun.factorytest.common.FTUtils;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import com.htfyun.factorytest.R;

import com.htfyun.factorytest.myrecorder.IRecordListener;
import com.htfyun.factorytest.myrecorder.RecorderThread;
import com.htfyun.factorytest.playerutils.MediaPlayerTool;
import com.htfyun.factorytest.utils.DebugLog;
import com.htfyun.factorytest.utils.executor.AppExecutors;

public class FragmentES7210_OneTest extends BaseFragment implements View.OnClickListener {
    private static final String RECORDER_FILE_PATH = FTUtils.getFTStorageDirectory() + File.separator + "mic_es7210.pcm";
    private static final String RECORDER_ONE_FILE_PATH = FTUtils.getFTStorageDirectory() + File.separator + "mic_es7210_one.pcm";

    private final int SampleRateInHz = 16000;

    private final static int STATE_WANT_RECORD = 0;
    private final static int STATE_WANT_PLAY = STATE_WANT_RECORD + 1;

    private TextView txtStatus;
    private TextView txtPassTips;
    private Button btnPass;
    private Button btnFail;
    private Button btnRepeat;
    private Button btnRecordAndPlay;

    private MediaPlayerTool mediaPlayerTool;

    private OnBtnResultForES7210 onBtnResultForES7210;

    public void setOnBtnResultForES7210(OnBtnResultForES7210 onBtnResultForES7210) {
        this.onBtnResultForES7210 = onBtnResultForES7210;
    }

    @Override
    protected int getLayoutRes() {
        return R.layout.fragment_engineer_es7210_one_test;
    }

    @Override
    protected void onInitView(@Nullable Bundle savedInstanceState) {

        txtStatus = findViewById(R.id.txtStatus);
        txtPassTips = findViewById(R.id.txtPassTips);
        btnPass = findViewById(R.id.btnPass);
        btnFail = findViewById(R.id.btnFail);
        btnRepeat = findViewById(R.id.btnRepeat);
        btnRecordAndPlay = findViewById(R.id.btnRecordAndPlay);

        btnPass.setOnClickListener(this);
        btnFail.setOnClickListener(this);
        btnRepeat.setOnClickListener(this);
        btnRecordAndPlay.setOnClickListener(this);

        DebugLog.e("getHandler = " + getHandler());

        mediaPlayerTool = MediaPlayerTool.getInstance(getContext(), getHandler());

        VolumeUtils.setVolume(AudioManager.STREAM_MUSIC, VolumeUtils.getMaxVolume(AudioManager.STREAM_MUSIC), 0);

    }


    @Override
    protected void onVisible() {
        super.onVisible();

        doOnVisible();
    }

    private void doOnVisible() {
        txtStatus.setText("");
        btnRepeat.setEnabled(false);

    }

    @Override
    protected void onInvisible() {
        super.onInvisible();
        stopRecord();
        stopPlay();
    }


    @Override
    public void onClick(View v) {

        if (v == btnRecordAndPlay) {

            stopPlay();
            startRecord();

            txtStatus.setText(R.string.mic_status_recording);
            setBtnRecordEnabled(false);

            getHandler().sendEmptyMessageDelayed(MSG_RECORD_OVER, DELAY_RECORD_OVER);


        } else if (v == btnPass) {

            txtPassTips.setText(R.string.record_pass);
            btnPass.setSelected(true);
            btnFail.setSelected(false);
            onBtnResultForES7210.onBtnResultForES7210(true);

        } else if (v == btnFail) {

            txtPassTips.setText(R.string.record_fail);
            btnPass.setSelected(false);
            btnFail.setSelected(true);
            onBtnResultForES7210.onBtnResultForES7210(false);

        } else if (v == btnRepeat) {
            startPlay();
        }

    }


    private void setBtnRecordEnabled(boolean enabled) {
        Button btnRecord = findViewById(R.id.btnRecordAndPlay);
        if (btnRecord == null) {
            return;
        }
        btnRecord.setEnabled(enabled);
    }

    //////////////////////
    //    play
    /////////////////////
    private void startPlay() {

        stopPlay();
        mediaPlayerTool.playPcm(RECORDER_ONE_FILE_PATH);

        getHandler().postDelayed(() -> txtStatus.setText(R.string.mic_status_playing), 300);

    }

    private void stopPlay() {
        mediaPlayerTool.stop();
        txtStatus.setText(R.string.mic_status_playing_stop);

    }

    //////////////////////
    //    Recorder
    /////////////////////
    private RecorderThread recorderThread;


    public void startRecord() {
        startRecordTread();
    }

    private void stopRecord() {
        stopRecordThread();

    }

    private void startRecordTread() {

        if (recorderThread != null) {
            stopRecordThread();
        }

        recorderThread = new RecorderThread("es7210-", null, RECORDER_FILE_PATH);
        recorderThread.getRecorderOperator().setSampleRateInHz(SampleRateInHz);
        recorderThread.getRecorderOperator().setChannelConfig(AudioFormat.CHANNEL_IN_STEREO);
        recorderThread.getRecorderOperator().setAudioFormat(AudioFormat.ENCODING_PCM_FLOAT);
        recorderThread.getRecorderOperator().setRecordingListener(recordListener);
        recorderThread.start();

    }

    private void stopRecordThread() {

        if (recorderThread != null) {
            recorderThread.joinThread();
            recorderThread = null;
        }
    }

    private volatile boolean keepAlive = true;
    private BlockingQueue<ByteBuffer> audioDataQueue = new LinkedBlockingQueue<>(128);

    private Runnable saveMonoRunnable = () -> {
        BufferedOutputStream bos = null;

        try {

            File file = new File(RECORDER_ONE_FILE_PATH);
            if (file.exists()) {
                file.delete();
            }
            bos = new BufferedOutputStream(new FileOutputStream(file));

            keepAlive = true;
            while (keepAlive) {

                ByteBuffer byteBuffer = audioDataQueue.take();
                if (byteBuffer != null && byteBuffer.array().length != 1) {
                    byte[] buffer = new byte[byteBuffer.array().length / 2];
                    for (int n = 0, i = 0; n < byteBuffer.array().length; ) {

                        n++;
                        n++;
                        buffer[i++] = byteBuffer.array()[n++];
                        buffer[i++] = byteBuffer.array()[n++];

                        n += 4;
                        i += 2;
                    }

                    bos.write(buffer, 0, buffer.length);
                    bos.flush();
                    buffer = null;
                    byteBuffer = null;

                }

            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {

            audioDataQueue.clear();

            DebugLog.e("write file finish..........................");

            if (bos != null) {
                try {
                    bos.flush();
                    bos.close();
                } catch (IOException ignored) {
                }
            }
        }
    };

    private IRecordListener recordListener = new IRecordListener() {

        @Override
        public void onRecordingData(byte[] audioData, int validSize) {

            int size = Math.min(audioData.length, validSize);

            audioDataQueue.add(ByteBuffer.wrap(audioData, 0, size));

        }

        @Override
        public void onRecordingStart() {

            AppExecutors.runOnIoThread(saveMonoRunnable);
            AppExecutors.postToMainThread(() -> Toast.makeText(mContext, R.string.record_start, Toast.LENGTH_SHORT).show());
        }

        @Override
        public void onRecordingStop() {

            keepAlive = false;
            //保证saveMonoRunnable能退出
            byte[] buffer = new byte[1];
            audioDataQueue.add(ByteBuffer.wrap(buffer, 0, buffer.length));

            AppExecutors.postToMainThread(() -> Toast.makeText(mContext, R.string.record_stop, Toast.LENGTH_SHORT).show());
        }
    };

    private final int MSG_RECORD_OVER = 10;
    private final int DELAY_RECORD_OVER = 5000;

    @Override
    protected void handleMessage(Message msg) {
        super.handleMessage(msg);
        DebugLog.e("msg.what = " + msg.what);
        if (msg.what == MediaPlayerTool.EVENT_PLAY_OVER) {
            txtStatus.setText(R.string.mic_status_playing_stop);
        } else if (msg.what == MSG_RECORD_OVER) {
            stopRecord();
            startPlay();
            setBtnRecordEnabled(true);
            btnRepeat.setEnabled(true);

        }
    }

}
